package com.up.vms.interfaces.rest.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import javax.servlet.http.HttpServletRequest;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomBasicAuthenticationEntryPoint customBasicAuthenticationEntryPoint;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        return new UserContextServiceImpl();
    }

    @Bean
    public CustomLogoutSuccessHandler customLogoutSuccessHandler() {
        return new CustomLogoutSuccessHandler();
    }

    /**
     * 自定义authenticationProvider
     *
     * @return
     */
    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider
                .setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(userDetailsService());
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);

        return daoAuthenticationProvider;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/static/**", "/webjars/**", "/css/**", "/js/**", "/images/**", "/fonts/**");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class)
                .headers()
                .frameOptions()
                .disable()
                .and()
                .authorizeRequests()
                .antMatchers("/system/initData").permitAll()
                .antMatchers("/actuator/**").permitAll()
                .antMatchers("/login").permitAll()
                .antMatchers("/ghwk/login").permitAll()
                .antMatchers("/testghwk/login").permitAll()
//                .antMatchers("/static/**").permitAll()
//                .antMatchers("/").permitAll()
//                .antMatchers("/index").permitAll()
//                .antMatchers("/index.html").permitAll()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/v2/api-docs").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/admin/logout").permitAll()
                .antMatchers("/app/**").permitAll()
                .antMatchers("/oauth/**").permitAll()
                .antMatchers("/vms/v1/video/pfop/notify").permitAll()
                .antMatchers("/ghwk/app/**").permitAll()
                .antMatchers("/ghwk/oauth/**").permitAll()
                .antMatchers("/ghwk/vms/v1/video/pfop/notify").permitAll()
                .antMatchers("/testghwk/app/**").permitAll()
                .antMatchers("/testghwk/oauth/**").permitAll()
                .antMatchers("/testghwk/vms/v1/video/pfop/notify").permitAll()
                .antMatchers("/testghwk/vms/v1/video/upload").permitAll()
                .antMatchers("/ghwk/vms/v1/video/upload").permitAll()
                .antMatchers("/vms/v1/video/upload").permitAll()
                .antMatchers("/testghwk/vms/v1/image/upload").permitAll()
                .antMatchers("/ghwk/vms/v1/image/upload").permitAll()
                .antMatchers("/vms/v1/image/upload").permitAll()
                .antMatchers("/testghwk/config").permitAll()
                .antMatchers("/ghwk/config").permitAll()
                .antMatchers("/config").permitAll()
//                .antMatchers("/**").permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()

                .and()
                .exceptionHandling().authenticationEntryPoint(customBasicAuthenticationEntryPoint)
//                .accessDeniedPage("/login")
                .and()
                .formLogin()
                .loginProcessingUrl("/login")
                .authenticationDetailsSource(authenticationDetailsSource())
                .successHandler(new CustomAuthenticationSuccessHandler())
                .failureHandler(
                        new CustomAuthenticationFailureHandler()
                )
                .and()
                .sessionManagement()
//            SessionCreationPolicy.IF_REQUIRED    仅当需要时，创建session
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                // 防止篡改session
                .sessionFixation()
                .changeSessionId()
                .maximumSessions(30)
                .maxSessionsPreventsLogin(true)
                .sessionRegistry(new SessionRegistryImpl())
                .expiredUrl("/?expired")
                .and()
                .and()
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .disable()
        ;

        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login")
                .logoutSuccessHandler(customLogoutSuccessHandler())
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .deleteCookies("JSESSIONID");
    }

    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource() {

        return request -> new WebAuthenticationDetails(request);
    }

}
